package model

import (
	"errors"
	"net"

	"github.com/songquanpeng/one-api/common/logger"
	"gorm.io/gorm"
)

type WhiteList struct {
	Id          int    `json:"id"`
	TokenId     int    `json:"token_id"`
	Ip          string `json:"ip" gorm:"not null;index"`
	Note        string `json:"note" gorm:"not null;index"`
	Status      int    `json:"status" gorm:"default:1"`
	CreatedTime int64  `json:"created_time" gorm:"bigint"`
}

func GetAllTokenWhiteLists(tokenId int, startIdx int, num int) ([]*WhiteList, int64, error) {
	var whiteLists []*WhiteList
	var err error
	err = DB.Where("token_id = ?", tokenId).Order("id desc").Limit(num).Offset(startIdx).Find(&whiteLists).Error

	count := int64(0)
	model := &WhiteList{}
	if err == nil {
		err = DB.Model(model).Where("token_id = ?", tokenId).Count(&count).Error
	}
	return whiteLists, count, err
}

func SearchTokenWhiteLists(tokenId int, keyword string) (whiteLists []*WhiteList, err error) {
	err = DB.Where("token_id = ?", tokenId).Where("name LIKE ?", keyword+"%").Find(&whiteLists).Error
	return whiteLists, err
}

func ValidateTokenWhiteList(tokenId int, clientIP string) (bool, error) {
	validated := false

	whiteLists, err := CacheGetWhiteListsByKey(tokenId)
	if err != nil {
		logger.SysError("CacheGetWhiteListsByKey failed: " + err.Error())
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return validated, errors.New("无效的令牌")
		}
		return validated, errors.New("令牌验证失败")
	}
	if len(whiteLists) == 0 {
		return true, nil
	}

	ip := net.ParseIP(clientIP)
	// CIDR范围
	for _, whiteList := range whiteLists {
		_, ipCidr, err := net.ParseCIDR(whiteList.Ip)
		if err != nil {
			if clientIP == whiteList.Ip {
				validated = true
				break
			}
			continue
		}
		// 检查IP地址是否在CIDR范围内
		if ipCidr.Contains(ip) {
			validated = true
			break
		}
	}

	return validated, nil
}

func GetWhiteListByIds(id int, tokenId int) (*WhiteList, error) {
	if id == 0 || tokenId == 0 {
		return nil, errors.New("id 或 tokenId 为空！")
	}
	whiteList := WhiteList{Id: id, TokenId: tokenId}
	var err error = nil
	err = DB.First(&whiteList, "id = ? and token_id = ?", id, tokenId).Error
	return &whiteList, err
}

func GetWhiteListById(id int) (*WhiteList, error) {
	if id == 0 {
		return nil, errors.New("id 为空！")
	}
	whiteList := WhiteList{Id: id}
	var err error = nil
	err = DB.First(&whiteList, "id = ?", id).Error
	return &whiteList, err
}

func (whiteList *WhiteList) Insert() error {
	var err error
	err = DB.Create(whiteList).Error
	return err
}

// Update Make sure your whiteList's fields is completed, because this will update non-zero values
func (whiteList *WhiteList) Update() error {
	var err error
	err = DB.Model(whiteList).Select("ip", "note").Updates(whiteList).Error
	return err
}

func (whiteList *WhiteList) SelectUpdate() error {
	// This can update zero values
	return DB.Model(whiteList).Select("ip").Updates(whiteList).Error
}

func (whiteList *WhiteList) Delete() error {
	var err error
	err = DB.Delete(whiteList).Error
	return err
}

func DeleteWhiteListById(id int, tokenId int) (err error) {
	// Why we need tokenId here? In case token want to delete other's whitelist.
	if id == 0 || tokenId == 0 {
		return errors.New("id 或 tokenId 为空！")
	}
	whiteList := WhiteList{Id: id, TokenId: tokenId}
	err = DB.Where(whiteList).First(&whiteList).Error
	if err != nil {
		return err
	}
	return whiteList.Delete()
}
